#!/usr/bin/env python

#PyCairoShape clock
#(c) 2007 Nicolas Trangez - ikke at nicolast dot be
#Released under GPL v2

#All imports we need
import sys
import gobject
import pango
import pygtk
pygtk.require('2.0')
import gtk
from gtk import gdk
import cairo
from datetime import datetime
import math

if gtk.pygtk_version < (2,10,0):
    print "PyGtk 2.10.0 or later required"
    raise SystemExit


class CairoControl:
    #Our widget (window) is clicked
    def clicked(self,widget, event):
        #If a shift key is pressed, start resizing
        if event.state & gtk.gdk.SHIFT_MASK:
                self.win.begin_resize_drag(gtk.gdk.WINDOW_EDGE_SOUTH_EAST, event.button, int(event.x_root), int(event.y_root), event.time)
        else:
        #else move
                self.win.begin_move_drag(event.button, int(event.x_root), int(event.y_root), event.time)

    #This is our main drawing function
    def expose(self,widget, event):

        (width, height) = widget.get_size()
        
        #Get a cairo context
        cr = widget.window.cairo_create()
        
        #Make the window transparent
        if self.supports_alpha == True:
            cr.set_source_rgba(1.0, 1.0, 1.0, 0.0)
        else:
            cr.set_source_rgb(1.0, 1.0, 1.0) 
        
        cr.set_operator(cairo.OPERATOR_SOURCE)
        cr.paint()

        #And draw everything we want
        #Some cos/sin magic is done, never mind
        cr.set_source_rgba(1.0, 0.2, 0.2, 0.7)
        if width < height:
            radius = float(width)/2 - 0.8
        else:
            radius = float(height)/2 - 0.8
            
        cr.arc(float(width)/2, float(height)/2, radius, 0, 2.0*3.14)
        cr.fill()
        cr.stroke()

        cr.move_to(float(width)/2, float(height)/2)
        if self.supports_alpha == True:
                cr.set_source_rgba(0.0, 0.0, 0.0, 0.9)
        else:
                cr.set_source_rgb(0.0, 0.0, 0.0)
        time = datetime.now()
        hour = time.hour
        minutes = time.minute
        seconds = time.second
        per_hour = (2 * 3.14) / 12
        dh = (hour * per_hour) + ((per_hour / 60) * minutes)
        dh += 2 * 3.14 / 4
        cr.set_line_width(0.05 * radius)
        cr.rel_line_to(-0.5 * radius * math.cos(dh), -0.5 * radius * math.sin(dh))
        cr.move_to(float(width)/2, float(height)/2)
        per_minute = (2 * 3.14) / 60
        dm = minutes * per_minute
        dm += 2 * 3.14 / 4
        cr.rel_line_to(-0.9 * radius * math.cos(dm), -0.9 * radius * math.sin(dm))
        cr.move_to(float(width)/2, float(height)/2)
        per_second = (2 * 3.14) / 60
        ds = seconds * per_second
        ds += 2 * 3.14 / 4
        cr.rel_line_to(-0.9 * radius * math.cos(ds), -0.9 * radius * math.sin(ds))
        cr.stroke()
       
        if self.supports_alpha == True:
                cr.set_source_rgba(0.5, 0.5, 0.5, 0.9)
        else:
                cr.set_source_rgb(0.5, 0.5, 0.5)
        cr.arc(float(width)/2, float(height)/2, 0.1 * radius, 0, 2.0*3.14)
        cr.fill()
        cr.stroke()

        #Once everything has been drawn, create our XShape mask
        #Our window content is contained inside the big circle,
        #so let's use that one as our mask
        pm = gtk.gdk.Pixmap(None, width, height, 1)
        pmcr = pm.cairo_create()
        pmcr.arc(float(width)/2, float(height)/2, radius, 0, 2.0*3.14)
        pmcr.fill()
        pmcr.stroke()
        #Apply input mask
        self.win.input_shape_combine_mask(pm, 0, 0)

        return False

    #If screen changes, it could be possible we no longer got rgba colors
    def screen_changed(self,widget, old_screen=None):
        
        screen = widget.get_screen()
        colormap = screen.get_rgba_colormap()
        if colormap == None:
            print 'Your screen does not support alpha channels!'
            colormap = screen.get_rgb_colormap()
            self.supports_alpha = False
        else:
            print 'Your screen supports alpha channels!'
            self.supports_alpha = True
        
        widget.set_colormap(colormap)
        
        return True

    #Queue a redraw of our window every second
    def update_clock(self):
        self.win.queue_draw()
        return True


    #This should be obvious
    def __init__(self):
        #Yeah, globals. Warning: this code is messy
        self.supports_alpha = False
        self.win = None
        self.shift_pressed = False

        self.win = gtk.Window()

        self.win.set_property("skip-taskbar-hint", True)
        
        self.win.set_title('PyCairoShape clock')
        self.win.connect('delete-event', gtk.main_quit)

        self.win.set_app_paintable(True)
        
        self.win.connect('expose-event', self.expose)
        self.win.connect('screen-changed', self.screen_changed)

        self.win.set_decorated(False)
        self.win.add_events(gdk.BUTTON_PRESS_MASK)
        self.win.connect('button-press-event', self.clicked)
        
        self.screen_changed(self.win)

        gobject.timeout_add(1000, self.update_clock)

        self.win.show_all()


if __name__ == "__main__":
    #sys.settrace(traceit)
    g = CairoControl()
    gtk.gdk.threads_init()
    gtk.main()
